Este notebook es un R Markdown que fue desarrollado en RStudio para ser ejecutado con código en Python3. Por lo tanto, además de tener instalado Python3, se debe instalar desde la consola de RStudio o en la terminal ejecutando R la biblioteca Reticulate para ligar Python con R, mediante el comando:
install.packages("reticulate")
Además, se requiere instalar las siguientes bibliotecas desde Python3 con los comandos respectivos desde la terminal.
-Pandas
pip3 install pandas
-Numpy
pip3 install numpy
-Matplotlib
pip3 install matplotlib
-Scikit Learn
pip3 install scikit-learn
-Tensorflow
En la terminal se instala la dependencia Testtresources:
sudo apt install python3-testresources
Luego, se instala Tensorflow con el siguiente comando:
pip3 install tensorflow
En este proyecto se hace un estudio del campo del Machine Learning, utilizando redes neuronales para la predicción de datos a partir del repositorio: COVID-19 Data Repository by the Center for Systems Science and Engineering (CSSE) at Johns Hopkins University. Se hace un tratamiento inicial de los datos y se presentan gráficamente. Posteriormente, se hace una proyección de casos de Covid-19, específicamente para Costa Rica, en donde se entrena una red neuronal a partir de una sección de los datos reales y con estos se hace la predicción a través de la red neuronal. Finalmente se comparan los datos proyectados con los datos reales para ese mismo periodo del tiempo.
El aprendizaje automático o machine learning, es un subcampo de las ciencias de la computación que busca que las computadoras puedan aprender, es decir, que puedan mejorar los resultados obtenidos a partir de la experiencia.
Una máquina utiliza un modelo matemático para relizar sus funciones. Estos modelos contienen parámetros, y la intención del aprendizaje de máquina es encontrar los parámetros que le permitan tener la mejor respuesta ante una entrada de información. Es a través de la modificación de estos parámetros, que una computadora puede “aprender”, es decir que puede obtener un mejor resultado, mejorando ella misma su rendimiento previo.
Imagen de: https://commons.wikimedia.org/wiki/File:Slope.gif
La forma en la que una máquina aprende varía dependiendo del modelo o arquitectura de aprendizaje de máquina que se esté utilizando. Pero de forma general, lo que se busca es calcular el error de la salida generada por la máquina con respecto a la salida deseada. Este error va a estar en función de los parámetros del modelo, es decir que lo que se busca es obtener cómo varía el error al variar los parámetros. Una vez que se obtiene una función que describa el error, se bucará encontrar el valor de los parámetros que disminuyan el error. Encontrar el menor error es equivalente a encontrar un mínimo de la función, lo cuál puede conseguirse derivando la función, o como es el caso de las redes neuronales, que poseen muchos parámetros, calculando el gradiente.
Entonces básicamente para que la máquina aprenda se requieren dos pasos: - Calcular el error - Optimizar el error (encontrar el mínimo)
Para estos dos pasos existen diversos métodos:
Las redes neuronales son un tipo de aprendizaje automático, que se basa en el uso de unidades de cálculo llamadas neuronas. Una red neuronal, como su nombre lo indica, está formada por un conjuto de estas neuronas conectadas.
Una red neuronal se compone de forma general por una capa de entrada, una o más capas de neuronas (también llamadas capas ocultas), y una capa de salida
Imagen de: https://commons.wikimedia.org/wiki/File:Colored_neural_network.svg
Imagen de: https://commons.wikimedia.org/wiki/File:Neural_network_bottleneck_achitecture.svg
Una neurona es una unidad que se encarga de realizar una suma ponderada de las entradas que llegan a esa neurona
Imagen de: https://commons.wikimedia.org/wiki/File:
Es decir que la salida está dada por
lo que se puede reescribir como
Para evitar la linealidad de las salidas de una neurona se utiliza una función de activación. Existen varias funciones de activación, pero por lo general son funciones acotadas. Entre las funciones de activación más usadas están:
Imagen de: https://commons.wikimedia.org/wiki/File:Ramp_function.svg
Imagen de: https://commons.wikimedia.org/wiki/File:Hyperbolic_Tangent.svg
Imagen de: https://commons.wikimedia.org/wiki/File:Sigmoid-function-2.svg
La función de activación se aplica justo antes de la salida
Imagen de: https://commons.wikimedia.org/wiki/File:Perceptr%C3%B3n_5_unidades.svg
Las Redes Neuronales Recurrentes (RNN), no posee una estructura de capas definida, sino que las conexiones entre las neuronas son de forma arbitraria. Esto en su representación más simple, aunque se pueden crear redes cíclicas más complejas para crear una red con memoria para casos más complejos. Este tipo de redes neuronales son muy potentes para el análisis de secuencias o patrones de datos, como textos, sonidos, videos. En la siguiente figura se muestra la arquitectura de una red neuronal recurrente sencilla.
Imagen de: https://www.diegocalvo.es/wp-content/uploads/2017/07/red-neuronal-recurrente.png
Dentro de las Redes Neuronales Recurrentes se encuentran diversos tipos, según el número de capas ocultas y la forma en que realizan retropropagación. Seguidamente se mencionan los más comunes.
Las redes LSTM son un tipo de red neuronal recurrente, con la característica que contiene una unidad de memoria. Esta unidad contiene tres puertas controladoras del cómo fluye la información dentro o fuera de ella. Seguidamente se mencionan estos tres elementos:
Imagen de: https://www.diegocalvo.es/wp-content/uploads/2018/12/Red-LSTM.png
Las Redes Neuronales Recurrentes (RNN) convencionales, a la hora del entrenamiento los gradientes retropropagados tienden a crecer mucho o incluso se pueden desvanecer con el tiempo. Esto se debe a que el gradiente depende de los errores presentes y pasados, pero estos últimos no se toman por la RNN. Para datos que se extienden en un largo periodo de tiempo, se da una acumulación grande de errores haciendo que este tipo de redes sean muy poco recomendables para análisis de series de datos por un largo periodo de tiempo. Es precisamente esto lo que vienen a solucionar las redes LSTM, ese cálculo y optimización del error a través de datos en un largo periodo de tiempo, es por ello que en este proyecto se implementó un modelo LSTM considerando que los datos sobre el Covid-19 son de un periodo un poco mayor a un año. En la imagen se muestra la diferencia en la complejidad de la arquitectura de ambos tipos de unidades.
Imagen de: https://i.stack.imgur.com/Iv3nU.png
Muchas son las bilbiotecas disponibles para implementar proyectos de Machine Learning en Python. En este proyecto se implementó una solución utilizando TensorFlow y Keras, además de las ya estudiadas en el curso. A continuación se muestran algunas de las bibliotecas más utilizadas en este campo.
Imagen de: https://miro.medium.com/max/700/1*RIrPOCyMFwFC-XULbja3rw.png
TensorFlow es una biblioteca de código abierto, un conjunto de herramientas, desarrollado por Google para construir y entrenar redes neuronales para detectar patrones, proyecciones y correlacionar de forma automática el razonamiento del ser humano para poder ser “implementado”. En primera instancia era para satisfacer las necesidades de la empresa, pero luego fue puesta a disposición del público el 9 de noviembre del 2015 y es una de las principales herramientas utilizadas en investigación y en el campo del Machine Learning alrededor del mundo. Algunas de las aplicaciones de TensorFlow son:
Keras es una API (Application Programming Interface) especializada para trabajar con redes neuronales. Keras corre sobre Tensorflow, es decir que utiliza las funciones que tensorflow provee y le agrega una capa más de abstracción, simplificando algunoas de los procesos más comunes y permitiendo que el usuario no tenga que preocuparse por algunos detalles, facilitando así la creación de redes neuronales, en especial para personas principiantes. Si se requiere un manejo más minuscioso de algunas funciones de la red neuronal, será necesario descender hasta el propio tensorflow.
A continuación se implementa el análisis de los datos en Python mediante la utilización de distintas bibliotecas. Se procede a mostrar el código fuente, así como la salida obtenida de este con una detallada descripción del mismo.
import pandas as pd
import numpy as np
import math
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, LSTM
Se carga el archivo csv en la variable. Retorna el data frame con las columnas de interés.
def CargarArchivo(file, online=False):
if online:
# Se carga el archivo online
datos = pd.read_csv(file)
else:
# Se carga el archivo local
datos = pd.read_csv('../Datos/' + file)
#Se convierte en data frame con pandas
datos_pd = pd.DataFrame(datos)
# Se eliminan las columnas con los nombres "Province/State", "Lat" y "Long"
datos_pd_reducidos = datos_pd.drop(['Province/State', 'Lat', 'Long'], axis=1)
# Retorna datos con las 3 columnas eliminadas
return datos_pd_reducidos
Se seleccionan los paises de interés para el análisis, con los casos acumulados.
def SeleccionarPaisesAcumulados(datos, paises=''):
#Se establece la columna 'Country/Region' como índice
datos = datos.set_index('Country/Region')
#Se elige solo la info de los países de la lista
if paises != '':
datos_paises = datos.loc[paises]
#Retorna datos solo de los países
return datos_paises
#Retorna datos solo de los países
else:
return datos
Se genera una función general para analizar los datos acumulados que se tienen para hacer las predicciones.
def Analice_archivoAcumulados(archivo, paises):
datos_reducidos = CargarArchivo(archivo, online =True)
datos_paises = SeleccionarPaisesAcumulados(datos_reducidos, paises)
#e. Se crea una lista con elementos desde 0 hasta el número de fechas menos 1
n_fechas = datos_paises.shape[1]
x_eje = list(range(0, n_fechas))
#f. Se grafican los datos
#--Se define los posibles títulos para el gráfico
titulo_grafico = ''
if archivo=='time_series_covid19_confirmed_global.csv' or archivo[-40:]=='time_series_covid19_confirmed_global.csv':
titulo_grafico = 'Casos Confirmados Acumulados de Covid-19'
elif archivo=='time_series_covid19_deaths_global.csv' or archivo[-37:]=='time_series_covid19_deaths_global.csv':
titulo_grafico = 'Casos de Muerte Acumulados por Covid-19'
elif archivo=='time_series_covid19_recovered_global.csv' or archivo[-40:]=='time_series_covid19_recovered_global.csv':
titulo_grafico = 'Casos Recuperados Acumulados de Covid-19'
#--Impresiones en Consola
#Columnas Eliminadas
print("-----------------> ANÁLISIS DE DATOS: "+titulo_grafico)
#Países de Interés
print("\n--> Países seleccionados: "+str(paises))
print(datos_paises)
#--For para graficar cada país
for i in range(len(paises)):
plt.plot(x_eje, datos_paises.loc[paises[i]],label=paises[i])
#--Títulos del gráfico
plt.title(titulo_grafico)
plt.xlabel('Días desde el '+datos_paises.columns[0]+' hasta el '+datos_paises.columns[n_fechas-1]+' [mes/día/año]')
plt.ylabel('Casos reportados')
plt.legend()
plt.show()
plt.close()
print("<----------------- FINALIZA ANÁLISIS DE DATOS <-----------------")
Se seleccionan los paises de interés para el análisis, con los casos diarios.
def SeleccionarPaisesDiarios(datos, paises=''):
#Se establece la columna 'Country/Region' como índice
datos = datos.set_index('Country/Region')
#Se elige solo la info de los países de la lista
if paises != '':
datos_paises = datos.loc[paises]
#Se calculan los casos diarios apartir de una resta de los acumulados
datos_paises = datos_paises.diff(axis=1).fillna(datos_paises.iloc[0,0]).astype(np.int64)
#Retorna datos solo de los países
return datos_paises
#Retorna datos solo de los países
else:
#Se calculan los casos diarios apartir de una resta de los acumulados
datos = datos.diff(axis=1).fillna(datos.iloc[0,0]).astype(np.int64)
return datos
Se genera una función general para analizar los datos diarios que se tienen para hacer las predicciones.
def Analice_archivoDiarios(archivo, paises):
datos_reducidos = CargarArchivo(archivo, online =True)
datos_paises = SeleccionarPaisesDiarios(datos_reducidos, paises)
#e. Se crea una lista con elementos desde 0 hasta el número de fechas menos 1
n_fechas = datos_paises.shape[1]
x_eje = list(range(0, n_fechas))
#f. Se grafican los datos
#--Se define los posibles títulos para el gráfico
titulo_grafico = ''
if archivo=='time_series_covid19_confirmed_global.csv' or archivo[-40:]=='time_series_covid19_confirmed_global.csv':
titulo_grafico = 'Casos Confirmados Diarios de Covid-19'
elif archivo=='time_series_covid19_deaths_global.csv' or archivo[-37:]=='time_series_covid19_deaths_global.csv':
titulo_grafico = 'Casos de Muerte Diarios por Covid-19'
elif archivo=='time_series_covid19_recovered_global.csv' or archivo[-40:]=='time_series_covid19_recovered_global.csv':
titulo_grafico = 'Casos Recuperados Diarios de Covid-19'
#--Impresiones en Consola
#Columnas Eliminadas
print("-----------------> ANÁLISIS DE DATOS: "+titulo_grafico)
#Países de Interés
print("\n--> Países seleccionados: "+str(paises))
print(datos_paises)
#--For para graficar cada país
for i in range(len(paises)):
plt.plot(x_eje, datos_paises.loc[paises[i]],label=paises[i])
#--Títulos del gráfico
plt.title(titulo_grafico)
plt.xlabel('Días desde el '+datos_paises.columns[0]+' hasta el '+datos_paises.columns[n_fechas-1]+' [mes/día/año]')
plt.ylabel('Casos reportados')
plt.legend()
plt.show()
plt.close()
print("<----------------- FINALIZA ANÁLISIS DE DATOS <-----------------")
Se genera una función que divide los datos, con el fin de poder ingresar más muestras al entrenamiento del modelo
Imagen de: https://stackoverflow.com/questions/31947183/how-to-implement-walk-forward-testing-in-sklearn
def walk_forward_format_2(train_data, in_size, out_size, step=1):
# Aplanamiento de datos
data = train_data.reshape(-1,1,1)
# Cantidad de muestras
samples = math.floor((data.shape[0]-(in_size+out_size))/step)
if (samples<1):
raise NameError("El tamaño de las entradas más las salidas es mayor al tamaño de los datos")
# Tamaño de los datos de validación
validation_size = out_size
# Tamaño de los datos de entrada
input_size = in_size
# Arreglo de entrada con muestras walk-forward
wf_data_in = []
# Arreglo de validacion con datos walk-forward
wf_data_val = []
# Se divide en cada una de las muestras
for i in range(0,samples):
wf_data_in.append(data[i*step:i*step+input_size])
wf_data_val.append(data[i*step+input_size:i*step+input_size+validation_size])
# Se convierten a np arrays con la forma deseada
wf_data_in_np = np.array(wf_data_in).reshape(samples,-1)
wf_data_val_np = np.array(wf_data_val).reshape(samples,-1)
return wf_data_in_np, wf_data_val_np
Se genera una función que divide los datos para obtener más muestras, cuando se tiene más de un país en el dataframe
def multi_walk_forward_format(train_data, in_size, out_size, step=1):
# Se inicializan listas vacías donde se colocarán las muestras
x_res = []
y_res = []
# Se hace un loop para recorrer cada país
for i in train_data:
# Se aplana el dato
data_temp = i.reshape(1,-1)
# Se llama a la función que divide los datos para un solo país
x_temp,y_temp = walk_forward_format_2(data_temp,in_size, out_size, step)
# Cada muestra obtenida para el país dse guarda en la lista con todas las muestras de todos los paises
# Esto se hace parta los datos de entrada
for j in x_temp:
x_res.append(j)
# Y para los de salida
for j in y_temp:
y_res.append(j)
# Finalmente se convierten las listas a arreglos de numpay y se les da la forma deseada
x_np = np.array(x_res).reshape(-1,in_size)
y_np = np.array(y_res).reshape(-1,out_size)
return x_np,y_np
# Main Parte 3: Se visualizan los datos
# Datos locales de respaldo
file1 = 'time_series_covid19_confirmed_global.csv'
file2 = 'time_series_covid19_deaths_global.csv'
file3 = 'time_series_covid19_recovered_global.csv'
# URL con los datos
url1 = 'https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv'
url2 = 'https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_deaths_global.csv'
url3 = 'https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_recovered_global.csv'
paises = ['Costa Rica']
Analice_archivoAcumulados(url1, paises)
## -----------------> ANÁLISIS DE DATOS: Casos Confirmados Acumulados de Covid-19
##
## --> Países seleccionados: ['Costa Rica']
## 1/22/20 1/23/20 1/24/20 ... 2/21/21 2/22/21 2/23/21
## Country/Region ...
## Costa Rica 0 0 0 ... 201678 202674 203097
##
## [1 rows x 399 columns]
## <----------------- FINALIZA ANÁLISIS DE DATOS <-----------------
Analice_archivoDiarios(url1,paises)
## -----------------> ANÁLISIS DE DATOS: Casos Confirmados Diarios de Covid-19
##
## --> Países seleccionados: ['Costa Rica']
## 1/22/20 1/23/20 1/24/20 ... 2/21/21 2/22/21 2/23/21
## Country/Region ...
## Costa Rica 0 0 0 ... 0 996 423
##
## [1 rows x 399 columns]
## <----------------- FINALIZA ANÁLISIS DE DATOS <-----------------
Analice_archivoAcumulados(url2, paises)
## -----------------> ANÁLISIS DE DATOS: Casos de Muerte Acumulados por Covid-19
##
## --> Países seleccionados: ['Costa Rica']
## 1/22/20 1/23/20 1/24/20 ... 2/21/21 2/22/21 2/23/21
## Country/Region ...
## Costa Rica 0 0 0 ... 2763 2782 2785
##
## [1 rows x 399 columns]
## <----------------- FINALIZA ANÁLISIS DE DATOS <-----------------
Analice_archivoDiarios(url2,paises)
## -----------------> ANÁLISIS DE DATOS: Casos de Muerte Diarios por Covid-19
##
## --> Países seleccionados: ['Costa Rica']
## 1/22/20 1/23/20 1/24/20 ... 2/21/21 2/22/21 2/23/21
## Country/Region ...
## Costa Rica 0 0 0 ... 0 19 3
##
## [1 rows x 399 columns]
## <----------------- FINALIZA ANÁLISIS DE DATOS <-----------------
Analice_archivoAcumulados(url3, paises)
## -----------------> ANÁLISIS DE DATOS: Casos Recuperados Acumulados de Covid-19
##
## --> Países seleccionados: ['Costa Rica']
## 1/22/20 1/23/20 1/24/20 ... 2/21/21 2/22/21 2/23/21
## Country/Region ...
## Costa Rica 0 0 0 ... 169053 172280 173591
##
## [1 rows x 399 columns]
## <----------------- FINALIZA ANÁLISIS DE DATOS <-----------------
Analice_archivoDiarios(url3,paises)
## -----------------> ANÁLISIS DE DATOS: Casos Recuperados Diarios de Covid-19
##
## --> Países seleccionados: ['Costa Rica']
## 1/22/20 1/23/20 1/24/20 ... 2/21/21 2/22/21 2/23/21
## Country/Region ...
## Costa Rica 0 0 0 ... 0 3227 1311
##
## [1 rows x 399 columns]
## <----------------- FINALIZA ANÁLISIS DE DATOS <-----------------
En esta sección se procede a implementar una Red Neuronal. Primero se seleccionan los datos para entrenar a la red neuronal, por lo tanto del total de días se seleccionan una gran parte para entrenar la red y con esto se proyecta para una cantidad de días el comportamiento de los casos por Covid-19, para posteriormente comparar este pronóstico con los datos reales.
# Se escoge cúales datos se utilizarán (confirmados, defunciones o recuperados)
url = url1
#url = url2
#url = url3
# Se cargan los datos a un dataframe
datos_totales = CargarArchivo(url,online=True)
# Se imprimen los datos para observarlos
print(datos_totales)
## Country/Region 1/22/20 1/23/20 ... 2/21/21 2/22/21 2/23/21
## 0 Afghanistan 0 0 ... 55604 55617 55646
## 1 Albania 0 0 ... 100246 101285 102306
## 2 Algeria 0 0 ... 111917 112094 112279
## 3 Andorra 0 0 ... 10699 10712 10739
## 4 Angola 0 0 ... 20519 20548 20584
## .. ... ... ... ... ... ... ...
## 269 Vietnam 0 2 ... 2383 2392 2403
## 270 West Bank and Gaza 0 0 ... 173635 174969 176377
## 271 Yemen 0 0 ... 2165 2176 2187
## 272 Zambia 0 0 ... 74503 75027 75582
## 273 Zimbabwe 0 0 ... 35796 35862 35910
##
## [274 rows x 400 columns]
Se comprueba que no hayan campos vacíos en el dataframe
print(datos_totales.isnull().values.any())
## False
# Días a excluir de los datos reales
dias_pronostico = 30
# Días que se ingresarán como entrada a la red
dias_disponibles = 320
#paises = ['Costa Rica','Guatemala', 'El Salvador', "Panama", 'Honduras']
paises = ['Costa Rica']
#datos_pais = SeleccionarPaisesAcumulados(CargarArchivo(url,online=True), paises)
datos_pais = SeleccionarPaisesDiarios(CargarArchivo(url,online=True), paises)
datos_pais
## 1/22/20 1/23/20 1/24/20 ... 2/21/21 2/22/21 2/23/21
## Country/Region ...
## Costa Rica 0 0 0 ... 0 996 423
##
## [1 rows x 399 columns]
Se seleccionan los datos para el entrenamiento
train_data = datos_pais.iloc[:,:-dias_pronostico].to_numpy()
print(train_data.shape)
## (1, 369)
Al trabajar con series de tiempo se puede ampliar la cantidad de muestras si los datos disponibles se dividen utilizando un método llamado ‘walk-forward’ o ‘roll-forward’. Este método consiste en tomar una muestra o ventana de datos, e irlos desplazado una cierta cantidad de pasos. De esta forma se pueden obtener una mayor cantidad de muestras.
train_x,train_y = multi_walk_forward_format(train_data,dias_disponibles,dias_pronostico,10)
print(train_x.shape)
## (1, 320)
Una forma recomendada de optimizar el proceso de entrenamiento es utilizar datos que estén entre un margen de 0 a 1, es por ello que los casos se escalan dentro de este margen.
# Se establece que la escala se hará utilizando los datos de entreno para los máximos y mínimos,
#es decir, al valor mínimo en datos_entreno se asigna como 0, y el máximo valor de datos_entreno se asigna como 1
sc_in = MinMaxScaler(feature_range=(0,1))
sc_out = MinMaxScaler(feature_range=(0,1))
# Se hace el ajuste de los datos, tanto para los datos de entrada com para los de salida, cada uno por aparte
sc_in.fit(train_x)
## MinMaxScaler()
sc_out.fit(train_y)
# Se escalan los datos de entrada y salida del entreno
## MinMaxScaler()
train_x_s = sc_in.transform(train_x)
train_y_s = sc_out.transform(train_y)
Una vez escalados los datos es necesario cambiar la forma como están acomodados los datos. Esto se hace únicamente porque así es la forma en la que la función de Keras que realiza el modelo recibe los datos.
Esta forma es de la siguiente manera:
(Cantidad de muestras, cantidad de pasos de tiempo, cantidad de características)
train_x_r = train_x_s.reshape(train_x_s.shape[0],train_x_s.shape[1],1)
train_y_r = train_y_s.reshape(train_y_s.shape[0],train_y_s.shape[1],1)
Ahora se definen los parámetros del modelo LSTM a crear.
verbose, epochs, batch_size = 1, 1, 1
n_timesteps, n_features, n_outputs = train_x_r.shape[1], train_x_r.shape[2], train_y_r.shape[1]
Modelo A, se ajustó mejor la predicción. Es el que se implementa en este proyecto.
#Inicialización del modelo
model = Sequential()
#Se agrega una capa interna LSTM
model.add(LSTM(30, return_sequences=False, activation='relu', input_shape=(n_timesteps, n_features)))
model.add(Dropout(0.2))
#Se agrega la capa externa de salida
model.add(Dense(n_outputs, activation='relu'))
EJEMPLO. Es posible agregar más capas internas LSTM pero incrementa el tiempo de entrenamiento, aunque puede o no mejorar la aproximación. Además, entre más capas internas en la red, nos adentramos en el campo del Deep Learning. El Modelo B no fue implementado ya que las predicciones se ajustaban más con solo una capa LSTM (Modelo A).
#Inicialización del modelo
model_B = Sequential()
#-Capa 1 LSTM: Se agrega una capa interna LSTM, se debe especificar el input_shape solo en la primera
model_B.add(LSTM(30, return_sequences=True, activation='relu', input_shape=(n_timesteps, n_features)))
model_B.add(Dropout(0.2))
#-Capa 2 LSTM
model_B.add(LSTM(50, return_sequences=True, activation='relu'))
model_B.add(Dropout(0.2))
#-Capa 3 LSTM
model_B.add(LSTM(50, activation='relu'))
model_B.add(Dropout(0.2))
#Se agrega la capa externa de salida
model_B.add(Dense(n_outputs, activation='relu'))
# Se establecen el método para obtener el error y para minimizarlo
model.compile(loss='mse', optimizer='adam')
# Se entrena el modelo con los datos de entreno
model.fit(train_x_r, train_y_r, epochs=epochs, batch_size=batch_size, verbose=verbose)
#Se despliega el modelo implementado, Modelo A
##
1/1 [==============================] - ETA: 0s - loss: 0.0000e+00
1/1 [==============================] - 1s 585ms/step - loss: 0.0000e+00
## <tensorflow.python.keras.callbacks.History object at 0x7ff5700ef640>
model.summary()
## Model: "sequential"
## _________________________________________________________________
## Layer (type) Output Shape Param #
## =================================================================
## lstm (LSTM) (None, 30) 3840
## _________________________________________________________________
## dropout (Dropout) (None, 30) 0
## _________________________________________________________________
## dense (Dense) (None, 30) 930
## =================================================================
## Total params: 4,770
## Trainable params: 4,770
## Non-trainable params: 0
## _________________________________________________________________
Ahora se procede a seleccionar los datos de entrada para la prueba.
pais = ['Costa Rica']
#datos_pais_test = SeleccionarPaisesAcumulados(CargarArchivo(url,online=True), pais)
datos_pais_test = SeleccionarPaisesDiarios(CargarArchivo(url,online=True), paises)
# Se seleccionan los últimos datos disponibles menos los que se usaran para comprobar si la predicción es correcta
test_x = datos_pais_test.iloc[:,-(dias_pronostico+dias_disponibles):-dias_pronostico].to_numpy()
# Se escalan los datos de entrada
test_x_s = sc_in.transform(test_x)
# Se acomodan en la forma que el modelo de Keras los recibe
test_x_r = test_x.reshape(test_x_s.shape[0],test_x_s.shape[1],1)
Grafica de Datos Reales utilizados para entrenar el Modelo LSTM
for i in test_x:
plt.plot(i)
# Se realiza la predicción del modelo
prediction = model.predict(test_x_r)
print(prediction.shape)
## (1, 30)
print(prediction)
## [[ 9.853279 46.92184 12.034856 0. 9.582053 0.
## 31.570387 19.801306 13.159703 5.0135546 0. 0.
## 0. 20.305485 0. 4.6466727 24.489756 30.629566
## 30.2438 10.981098 0. 0. 18.225166 11.540635
## 10.700467 0. 17.172892 0. 0. 0. ]]
# El resultado está escalado, por lo que es necesario invertir el escalamiento para obtener los valores en la escala correcta
prediction_rescaled = sc_out.inverse_transform(prediction)
print(prediction_rescaled)
## [[2745.8533 1055.9219 1270.0349 1127. 1141.582 0.
## 31.570387 2241.8013 940.1597 1172.0135 1125. 1084.
## 0. 20.305485 2421. 915.64667 1162.4897 1078.6295
## 30.2438 10.981098 0. 2772. 1055.2252 1326.5406
## 1217.7004 0. 17.172892 0. 3115. 1155. ]]
# Se obtienen los datos reales que se querían predecir, para poder comparar
test_y = datos_pais.iloc[:,-dias_pronostico:].to_numpy()
print(prediction)
## [[ 9.853279 46.92184 12.034856 0. 9.582053 0.
## 31.570387 19.801306 13.159703 5.0135546 0. 0.
## 0. 20.305485 0. 4.6466727 24.489756 30.629566
## 30.2438 10.981098 0. 0. 18.225166 11.540635
## 10.700467 0. 17.172892 0. 0. 0. ]]
print(test_y)
## [[1437 600 721 571 639 0 0 1293 440 528 455 446 0 0
## 997 417 486 418 431 0 0 837 430 434 353 437 0 0
## 996 423]]
Grafica de Datos de Predicción vs Datos Reales correspondientes a ese mismo periodo
plt.figure("Resultados")
plt.plot(test_y[0])
plt.plot(prediction_rescaled[0])
plt.legend(("Real", "Pred"))
plt.show()
plt.close()
Grafica de Datos de Predicción vs Datos Reales TOTALES, todo el archivo
plt.figure("Resultados General Costa Rica")
n_fechas = datos_pais_test.shape[1]
x_eje_r = list(range(0, n_fechas))
x_eje_p = list(range(n_fechas-dias_pronostico, n_fechas))
plt.plot(x_eje_r, datos_pais_test.loc[pais[0]])
plt.plot(x_eje_p, prediction_rescaled[0])
plt.legend(("Real", "Pred"))
plt.show()
plt.close()
[1] Saffa, F. (2020). “Exploring the Link between COVID-19 and Depression using Neural Networks”. Recuperado de: https://towardsdatascience.com/exploring-the-link-between-covid-19-and-depression-using-neural-networks-469030112d3d
[2] “COVID-19 Data Repository by the Center for Systems Science and Engineering (CSSE) at Johns Hopkins University”. Recuperado de: https://github.com/CSSEGISandData/COVID-19
[3] Dong E, Du H, Gardner L. “An interactive web-based dashboard to track COVID-19 in real time”. Lancet Inf Dis. 20(5):533-534. doi: 10.1016/S1473-3099(20)30120-1
[4] Calvo, D. (2018).“Red Neuronal Recurrente – RNN”. Recuperado de: https://www.diegocalvo.es/red-neuronal-recurrente/